;;
;; Initialized data
;;
section .data
    sysWrite        equ 1
    stdOut          equ 1
    sysExitCall     equ 60
    exitCode        equ 0
    
    newLine         db 0xa
    input           db "Hello world!"
    
;;
;; Non-initialized data
;;
section .bss
    output  resb 1  
    
;;
;; Code
;;
section .text
    global  _start

;;
;; Main routine
;;
_start:
    mov     rsi, input              ; get the address of input
    xor     rcx, rcx                ; zeroize rcx for counter
    cld                             ; df = 0
    mov     rdi, $ + 15             ; remember place after function call
    call    calculateStrLength      ; get string length
    xor     rax, rax                ; write zeros to rax
    xor     rdi, rdi                ; additional counter for reverseStr
    jmp     reverseStr              ; reverse string
    
;;
;; Calculate length of string
;;
calculateStrLength:
    cmp     byte [rsi], 0           ; check is it end of string
    je      exitFromRoutine         ; if yes exit from function
    lodsb                           ; load byte from rsi to al and inc rsi
    push    rax                     ; push symbol to stack
    inc     rcx                     ; increase counter
    jmp     calculateStrLength      ; loop again
    
;;
;; Back to _start
;;
exitFromRoutine:
    push    rdi                     ; push return address to stack again
    ret                             ; return to _start
    
;;
;; Reverse string
;;
reverseStr:
    cmp     rcx, 0                  ; check is it end of string
    je      printResult             ; if yes print result string
    pop     rax                     ; get symbol from stack
    mov     [output + rdi], rax     ; write it to output buffer
    dec     rcx                     ; decrease length counter
    inc     rdi                     ; increase additional length counter (for write syscall)
    jmp     reverseStr              ; loop again
    
;;
;; Print result string
;;
printResult:
    mov     rdx, rdi
    mov     rax, sysWrite
    mov     rdi, stdOut
    mov     rsi, output
    syscall
    jmp     printNewLine
    
;;
;; Print new line
;;
printNewLine:
    mov     rax, sysWrite
    mov     rdi, stdOut
    mov     rsi, newLine
    mov     rdx, 1
    syscall
    jmp     exit
    
;;
;; Exit program
;;
exit:
    mov     rax, sysExitCall
    mov     rdi, exitCode
    syscall
